Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(custom-elemen): ce support child component style tags and attribute settings #7942

Closed
wants to merge 94 commits into from

Conversation

baiwusanyu-c
Copy link
Member

@baiwusanyu-c baiwusanyu-c commented Mar 22, 2023

This PR contains two parts.
Based on the existing CE style implementation design, cooperate with plugin-vue (using the styles attribute provided by the compiler) to implement CE's sub-component style injection.
close: #7941
close: #4662
close: #6530

more: vuejs/rfcs#596

@vercel
Copy link

vercel bot commented Apr 6, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

1 Ignored Deployment
Name Status Preview Updated (UTC)
sfc-playground ⬜️ Ignored (Inspect) Apr 6, 2023 0:44am

@johnp
Copy link

johnp commented Apr 26, 2023

Works similarly well as #6610 and solves #4662. (requires enabling custom element mode in vite-plugin-vue; works for build and HMR)

With this PR, under some circumstances, the style tags are duplicated, see for example:

Edit:

Probably all the same underlying issue, if I had to guess.

@SavkaTaras
Copy link

Hello @LinusBorg ,
I hope you are well.

Could you please look at this PR and decide if that's a valid fix for #4662 once you have some time?

Thank you so much,
Taras Savka

Copy link

@johnp johnp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are the issues as tests (expect the possible style grouping issue):

    test('nested child components w/ fragments in shadow dom should have styles', async () => {
      const GrandChild = {
        styles: [`.my-green { color: green; }`],
        render() {
          return h('p', { class: "my-green" }, "This should be green")
        }
      }
      const Child = {
        components: { GrandChild },
        styles: [`.my-blue { color: blue; }`],
        render() {
          return h('div', {}, [
            h('p', { class: "my-blue" }, "This should be blue"),
            h('div', {}, h(GrandChild))
          ])
        }
      }
      const Foo = defineCustomElement({
        components: { Child },
        styles: [`.my-red { color: red; }`],
        render() {
          return [
            h('p', { class: "my-red" }, "This should be red"),
            h(Child)
          ]
        }
      })
      customElements.define('my-el-with-grandchild-styles', Foo)
      container.innerHTML = `<my-el-with-grandchild-styles></my-el-with-grandchild-styles>`
      await nextTick()

      const el = container.childNodes[0] as VueElement
      const style = el.shadowRoot?.querySelectorAll('style')!
      expect(style.length).toBe(3)
      expect(style[0].textContent).toBe(`.my-red { color: red; }`)
      expect(style[1].textContent).toBe(`.my-blue { color: blue; }`)
      expect(style[2].textContent).toBe(`.my-green { color: green; }`)
    })

    test('deeply nested child components w/ fragments in shadow dom should have styles', async () => {
      const GreatGrandChild = {
        styles: [`.my-grey { color: grey; }`],
        render() {
          return h('p', { class: "my-grey" }, "This should be grey")
        }
      }
      const GrandChild = {
        components: { GreatGrandChild },
        styles: [`.my-green { color: green; }`],
        render() {
          return [
            h('p', { class: "my-green" }, "This should be green"),
            h('span', {}, h(GreatGrandChild))
          ]
        }
      }
      const Child = {
        components: { GrandChild },
        styles: [`.my-blue { color: blue; }`],
        render() {
          return h('div', {}, [
            h('p', { class: "my-blue" }, "This should be blue"),
            h('div', {}, h(GrandChild))
          ])
        }
      }
      const Foo = defineCustomElement({
        components: { Child },
        styles: [`.my-red { color: red; }`],
        render() {
          return [
            h('p', { class: "my-red" }, "This should be red"),
            h(Child)
          ]
        }
      })
      customElements.define('my-el-with-greatgrandchild-styles', Foo)
      container.innerHTML = `<my-el-with-greatgrandchild-styles></my-el-with-greatgrandchild-styles>`
      await nextTick()

      const el = container.childNodes[0] as VueElement
      const style = el.shadowRoot?.querySelectorAll('style')!
      expect(style.length).toBe(4)
      expect(style[0].textContent).toBe(`.my-red { color: red; }`)
      expect(style[1].textContent).toBe(`.my-blue { color: blue; }`)
      expect(style[2].textContent).toBe(`.my-green { color: green; }`)
      expect(style[3].textContent).toBe(`.my-grey { color: grey; }`)
    })

@OBe95
Copy link

OBe95 commented Nov 23, 2023

Just mentioning this bug here, I also reproduce using this PR
Let me know if you want to report this fix here as well :)

@yoyo837
Copy link

yoyo837 commented Dec 14, 2023

Can this be merged?

Copy link

codspeed-hq bot commented Dec 15, 2023

CodSpeed Performance Report

Merging #7942 will not alter performance

Comparing baiwusanyu-c:bwsy/feat/CEChildStyle (1a97321) with main (bae79dd)

Summary

✅ 53 untouched benchmarks

@yoyo837
Copy link

yoyo837 commented Dec 23, 2023

Shadow DOM should support link style.

baiwusanyu-c and others added 4 commits January 3, 2024 11:45
# Conflicts:
#	packages/compiler-sfc/src/compileScript.ts
#	packages/compiler-sfc/src/parse.ts
#	packages/compiler-sfc/src/script/normalScript.ts
#	packages/compiler-sfc/src/style/cssVars.ts
#	packages/runtime-core/src/renderer.ts
#	packages/runtime-dom/__tests__/customElement.spec.ts
@yoyo837
Copy link

yoyo837 commented Jan 3, 2024

I've been following this PR and thank you for your hard work so much. However, does the vue team have a positive view on this PR?

@lseguin1337
Copy link

Hello everyone ✋ I have a simpler solution for those who want to bootstrap their vue app inside a shadowRoot:

here is a simple vitejs plugin that will inject all styles using the adoptedStylesheets API.
Let me know if you face some limitation, and if you need a version for webpack.

https://github.com/lseguin1337/vue-adopted-stylesheets

@matthiasPOE
Copy link

ping @LinusBorg

@leonheess
Copy link

@yyx990803 please 😭😭

Comment on lines +80 to +99
// TODO unit test

/*
const __sfc__ = {};
import { openBlock as _openBlock, createElementBlock as _createElementBlock, defineCustomElement as _defineCustomElement } from "vue"
function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock("h1", null, " app "))
}
__sfc__.render = render
__sfc__.__file = "src/App.vue"
export default customElements.define(name, _defineCustomElement(constructor), options);
*/

// :id="{ id: msg3, 'other-attr': msg }"
// id="{ id: msg3, 'other-attr': msg }"
// .id="{ id: msg3, 'other-attr': msg }"
// v-bind:src="msg2s"
// v-bind:[msg]="msg2"
// :[msg]="msg2"
// :xlink:special="msg3"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question (if-minor): should this be removed or enabled? Like now it looks like temporary outcommented code that might never be worked on in the future, if not worked on now.

yyx990803 added a commit that referenced this pull request Aug 5, 2024
yyx990803 added a commit that referenced this pull request Aug 5, 2024
@baiwusanyu-c baiwusanyu-c deleted the bwsy/feat/CEChildStyle branch August 8, 2024 09:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
❗ p4-important Priority 4: this fixes bugs that violate documented behavior, or significantly improves perf. scope: custom elements version: minor
Projects
Status: Rejected
Status: Done